home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Utilities / Other / mCD / Source / scsi_cd.subproj / cd_commands.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-11  |  28.3 KB  |  907 lines

  1. /*
  2.  * cd_commands.c: CD-ROM drive specific commands
  3.  *
  4.  * This is based on the file that NeXT included in
  5.  *      /NextDeveloper/Examples/UNIX/SCSI_CD,
  6.  *      done by James C. Lee at NeXT, Sep 1991.
  7.  * It has been changed "just a bit" by Garance Alistair Drosehn/March 1994.
  8.  *
  9.  */
  10.  
  11. #define CD_DEBUG2
  12.  
  13. #import <libc.h>
  14. #import <objc/objc.h>
  15. #import <c.h>
  16. #import "cd_commands.h"
  17. #import "cd_cmdsint.h"        /* structs internal to cd_commands */
  18. #import "scsi_commands.h"
  19.  
  20. /**************************************************************************
  21.  *   do_eject_1b
  22.  *
  23.  */
  24. int
  25. do_eject_1b(int fd, struct timeval * tvp, struct esense_reply * erp)
  26. {
  27.     struct scsi_req     sr;
  28.     struct start_stop_1B_cmd *sscp;
  29.     int                 err;
  30.  
  31.     bzero((char *)&sr, sizeof(sr));
  32.  
  33.     sscp = (struct start_stop_1B_cmd *) & sr.sr_cdb;
  34.     sscp->ssc_opcode = C6OP_STARTSTOP;
  35.     sscp->ssc_imm = 0;        /* status will be returned after the
  36.                  * operation is completed */
  37.     sscp->ssc_loej = 1;        /* eject when spin down (scc_start=0) */
  38.     sscp->ssc_start = 0;    /* spin down */
  39.  
  40.     sr.sr_addr = NULL;
  41.     sr.sr_dma_max = 0;        /* don't really do I/O to memory */
  42.     sr.sr_ioto = 10;        /* time out in 10 seconds */
  43.     sr.sr_dma_dir = SR_DMA_RD;
  44.  
  45.     err = ioctl(fd, SDIOCSRQ, &sr);
  46.  
  47.     *tvp = sr.sr_exec_time;
  48.  
  49.     if (sr.sr_dma_xfr != 0)
  50.     fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
  51.  
  52.     *erp = sr.sr_esense;
  53.     return err | sr.sr_io_status;
  54. }
  55.  
  56.  
  57. /**************************************************************************
  58.  *   do_spinup_1b
  59.  *
  60.  *    same command as do_eject, except that sscp->ssc_start=1 and
  61.  *    sscp->ssc_loej=0
  62.  */
  63. int
  64. do_spinup_1b(int fd, struct timeval * tvp, struct esense_reply * erp)
  65. {
  66.     struct scsi_req     sr;
  67.     struct start_stop_1B_cmd *sscp;
  68.     int                 err;
  69.  
  70.     bzero((char *)&sr, sizeof(sr));
  71.  
  72.     sscp = (struct start_stop_1B_cmd *) & sr.sr_cdb;
  73.     sscp->ssc_opcode = C6OP_STARTSTOP;
  74.     sscp->ssc_imm = 0;        /* status will be returned after the
  75.                  * operation is completed */
  76.     sscp->ssc_loej = 0;
  77.     sscp->ssc_start = 1;    /* spin up */
  78.  
  79.     sr.sr_addr = NULL;
  80.     sr.sr_dma_max = 0;        /* don't really do I/O to memory */
  81.     sr.sr_ioto = 10;        /* time out in 10 seconds */
  82.     sr.sr_dma_dir = SR_DMA_RD;
  83.  
  84.     err = ioctl(fd, SDIOCSRQ, &sr);
  85.  
  86.     *tvp = sr.sr_exec_time;
  87.  
  88.     if (sr.sr_dma_xfr != 0)
  89.     fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
  90.  
  91.     *erp = sr.sr_esense;
  92.     return err | sr.sr_io_status;
  93. }
  94.  
  95.  
  96. /**************************************************************************
  97.  *   do_stopunit_1b
  98.  *
  99.  *    same command as do_eject_1b, except that sscp->ssc_loej=0
  100.  *    because the caddy should not be ejected.
  101.  */
  102. int
  103. do_stopunit_1b(int fd, struct timeval * tvp, struct esense_reply * erp)
  104. {
  105.     struct scsi_req     sr;
  106.     struct start_stop_1B_cmd *sscp;
  107.     int                 err;
  108.  
  109.     bzero((char *)&sr, sizeof(sr));
  110.  
  111.     sscp = (struct start_stop_1B_cmd *) & sr.sr_cdb;
  112.     sscp->ssc_opcode = C6OP_STARTSTOP;
  113.     sscp->ssc_imm = 0;        /* status will be returned after the
  114.                  * operation is completed */
  115.     sscp->ssc_loej = 0;        /* do not eject when spin down (scc_start=0) */
  116.     sscp->ssc_start = 0;    /* spin down */
  117.  
  118.     sr.sr_addr = NULL;
  119.     sr.sr_dma_max = 0;        /* don't really do I/O to memory */
  120.     sr.sr_ioto = 10;        /* time out in 10 seconds */
  121.     sr.sr_dma_dir = SR_DMA_RD;
  122.  
  123.     err = ioctl(fd, SDIOCSRQ, &sr);
  124.  
  125.     *tvp = sr.sr_exec_time;
  126.  
  127.     if (sr.sr_dma_xfr != 0)
  128.     fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
  129.  
  130.     *erp = sr.sr_esense;
  131.     return err | sr.sr_io_status;
  132. }
  133.  
  134.  
  135. /**************************************************************************
  136.  *   do_pauseaudio_4b
  137.  */
  138. int
  139. do_pauseaudio_4b(int fd, int pause, struct esense_reply * erp)
  140. {
  141.     struct scsi_req     sr;
  142.     struct pause_4b_cmd *pp;
  143.     int                 err;
  144.  
  145.     bzero((char *)&sr, sizeof(sr));
  146.  
  147.     pp = (struct pause_4b_cmd *) & sr.sr_cdb;
  148.     pp->p_op_code = C10OP_PAUSE_4B;
  149.     pp->p_resume = !pause;    /* resume = not(pause) */
  150.  
  151.     sr.sr_addr = NULL;
  152.     sr.sr_dma_max = 0;
  153.     sr.sr_ioto = 5;        /* time out in 5 seconds */
  154.     sr.sr_dma_dir = SR_DMA_RD;
  155.  
  156.     err = ioctl(fd, SDIOCSRQ, &sr);
  157.  
  158.     if (sr.sr_dma_xfr != 0)
  159.     fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
  160.  
  161.     *erp = sr.sr_esense;
  162.     return err | sr.sr_io_status;
  163. }
  164.  
  165.  
  166. /**************************************************************************
  167.  *   do_pauseaudio_c5
  168.  *
  169.  *    this command implements the same capability as do_pauseaudio_4b,
  170.  *    but the x'c5' opcode is the the standardized one.  This works on
  171.  *    the CD-ROM drive that NeXT sold, but not on other CD-ROM drives.
  172.  */
  173. int
  174. do_pauseaudio_c5(int fd, int pause, struct esense_reply * erp)
  175. {
  176.     struct scsi_req     sr;
  177.     struct pause_c5_cmd *pp;
  178.     int                 err;
  179.  
  180.     bzero((char *)&sr, sizeof(sr));
  181.  
  182.     pp = (struct pause_c5_cmd *) & sr.sr_cdb;
  183.     pp->p_op_code = C10OP_PAUSE_C5;
  184.     pp->p_pause = pause;
  185.  
  186.     sr.sr_addr = NULL;
  187.     sr.sr_dma_max = 0;
  188.     sr.sr_ioto = 5;        /* time out in 5 seconds */
  189.     sr.sr_dma_dir = SR_DMA_RD;
  190.  
  191.     err = ioctl(fd, SDIOCSRQ, &sr);
  192.  
  193.     if (sr.sr_dma_xfr != 0)
  194.     fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
  195.  
  196.     *erp = sr.sr_esense;
  197.     return err | sr.sr_io_status;
  198. }
  199.  
  200.  
  201. /**************************************************************************
  202.  *   do_preventremoval_1e
  203.  *
  204.  *    prevent (or allow) medium removal.  ie, disable (enable) the
  205.  *    button on the front of the CD-ROM drive.
  206.  */
  207. int
  208. do_preventremoval_1e(int fd, int prevent, struct esense_reply * erp)
  209. {
  210.     struct scsi_req     sr;
  211.     struct prevent_removal_1e_cmd *pp;
  212.     int                 err;
  213.  
  214.     bzero((char *)&sr, sizeof(sr));
  215.  
  216.     pp = (struct prevent_removal_1e_cmd *) & sr.sr_cdb;
  217.     pp->par_op_code = C6OP_PREVENT_REMOVAL_1E;
  218.     pp->par_prevent = prevent;    /* 0 = allow, 1 = prevent */
  219.  
  220.     sr.sr_addr = NULL;
  221.     sr.sr_dma_max = 0;
  222.     sr.sr_ioto = 5;        /* time out in 5 seconds */
  223.     sr.sr_dma_dir = SR_DMA_RD;
  224.  
  225.     err = ioctl(fd, SDIOCSRQ, &sr);
  226.  
  227.     if (sr.sr_dma_xfr != 0)
  228.     fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
  229.  
  230.     *erp = sr.sr_esense;
  231.     return err | sr.sr_io_status;
  232. }
  233.  
  234.  
  235. /**************************************************************************
  236.  *   do_rezerounit_01
  237.  */
  238. int
  239. do_rezerounit_01(int fd, struct esense_reply * erp)
  240. {
  241.     struct scsi_req     sr;
  242.     struct rezero_unit_01_cmd *rz;
  243.     int                 err;
  244.  
  245.     bzero((char *)&sr, sizeof(sr));
  246.  
  247.     rz = (struct rezero_unit_01_cmd *) & sr.sr_cdb;
  248.     rz->rzu_opcode = C6OP_REZEROUNIT_01;
  249.  
  250.     sr.sr_addr = NULL;
  251.     sr.sr_dma_max = 0;
  252.     sr.sr_ioto = 5;        /* time out in 5 seconds */
  253.     sr.sr_dma_dir = SR_DMA_RD;
  254.  
  255.     err = ioctl(fd, SDIOCSRQ, &sr);
  256.  
  257.     if (sr.sr_dma_xfr != 0)
  258.     fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
  259.  
  260.     *erp = sr.sr_esense;
  261.     return err | sr.sr_io_status;
  262. }
  263.  
  264.  
  265. /**************************************************************************
  266.  *   do_playaudio_c8
  267.  */
  268. int
  269. do_playaudio_c8(int fd, int lba, int length, struct esense_reply * erp)
  270. {
  271.     struct scsi_req     sr;
  272.     struct playaudio_c8_cmd *pap;
  273.     int                 err;
  274.  
  275.     bzero((char *)&sr, sizeof(sr));
  276.  
  277.     pap = (struct playaudio_c8_cmd *) & sr.sr_cdb;
  278.     pap->pa_op_code = C6OP_PLAYAUDIO_C8;
  279.     SET_4BYTE_UINT(pap->pa_lba, lba);    /* block to play audio from */
  280.     SET_2BYTE_UINT(pap->pa_length, length);    /* length to play */
  281.  
  282.     sr.sr_addr = NULL;
  283.     sr.sr_dma_max = 0;
  284.     sr.sr_ioto = 10;        /* time out in 10 seconds */
  285.     sr.sr_dma_dir = SR_DMA_RD;
  286.  
  287.     err = ioctl(fd, SDIOCSRQ, &sr);
  288.  
  289.     if (sr.sr_dma_xfr != 0)
  290.     fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
  291.  
  292.     *erp = sr.sr_esense;
  293.     return err | sr.sr_io_status;
  294. }
  295.  
  296.  
  297. /**************************************************************************
  298.  *   do_playaudio_msf_47
  299.  */
  300. int
  301. do_playaudio_msf_47(int fd, struct pa_msf startmsf, struct pa_msf endmsf,
  302.             struct esense_reply * erp)
  303. {
  304.     struct scsi_req     sr;
  305.     struct playaudio_msf_47_cmd *pap;
  306.     int                 err;
  307.  
  308.     bzero((char *)&sr, sizeof(sr));
  309.  
  310.     pap = (struct playaudio_msf_47_cmd *) & sr.sr_cdb;
  311.     pap->pam_op_code = C10OP_PLAYAUDIO_MSF_47;
  312.     pap->pam_start_min = startmsf.min;
  313.     pap->pam_start_sec = startmsf.sec;
  314.     pap->pam_start_frame = startmsf.frame;
  315.     pap->pam_end_min = endmsf.min;
  316.     pap->pam_end_sec = endmsf.sec;
  317.     pap->pam_end_frame = endmsf.frame;
  318.  
  319.     sr.sr_addr = NULL;
  320.     sr.sr_dma_max = 0;
  321.     sr.sr_ioto = 10;        /* time out in 10 seconds */
  322.     sr.sr_dma_dir = SR_DMA_RD;
  323.  
  324.     err = ioctl(fd, SDIOCSRQ, &sr);
  325.  
  326.     if (sr.sr_dma_xfr != 0)
  327.     fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
  328.  
  329.     *erp = sr.sr_esense;
  330.     return err | sr.sr_io_status;
  331. }
  332.  
  333.  
  334. /**************************************************************************
  335.  *   do_readtoc_43
  336.  *
  337.  *    read in the entire table-of-contents of an audio CD, and return
  338.  *    to the user in a platform-independent format.
  339.  */
  340. int
  341. do_readtoc_43(int fd, struct cd_toc * toc_all, struct esense_reply * erp)
  342. {
  343.     struct scsi_req     sr;
  344.     struct readtoc_43_cmd *rt10cp;
  345.     struct readtoc_43_reply tocr;
  346.     int                 err;
  347.     char               *toc_reply;    /* toc reply from scsi bus, need to
  348.                      * be allocated */
  349.     u_int               toc_data_length,
  350.             toc_temp_length,
  351.                         lastsec,
  352.                         currsec;
  353.     struct rtr_desc    *desc;    /* pointer to traverse through *toc_reply */
  354.     int                 nrecords,    /* number of desc blocks info in toc */
  355.             nrectemp,
  356.                         i,
  357.                         track,
  358.                         lasttrack;
  359.  
  360.  /*
  361.   * First zero most everything in the cd_toc parameter, except the times.
  362.   * Note the time variables are really unsigned integers.. 
  363.   */
  364.     bzero((char *)toc_all, sizeof(struct cd_toc));
  365.     for (i = 0; i <= 100; i++) {
  366.     toc_all->info[i].hour = -1;
  367.     toc_all->info[i].min = -1;
  368.     toc_all->info[i].sec = -1;
  369.     toc_all->info[i].frame = -1;
  370.     }
  371.  
  372.     bzero((char *)&sr, sizeof(sr));
  373.     toc_reply = NULL;
  374.  
  375.     rt10cp = (struct readtoc_43_cmd *) & sr.sr_cdb;
  376.     rt10cp->rt_op_code = C10OP_READTOC_43;
  377.     rt10cp->rt_msf = 0;        /* don't use msf format */
  378.     rt10cp->rt_starttrack = 0;
  379.  /* read only info on track 0 to find out TOC data length */
  380.     toc_data_length = sizeof(struct readtoc_43_reply);
  381.     SET_2BYTE_UINT(rt10cp->rt_length, toc_data_length);
  382.  
  383.     sr.sr_addr = (char *)&tocr;
  384.     sr.sr_dma_max = sizeof(tocr);
  385.     sr.sr_ioto = 5;        /* time out in 5 seconds */
  386.     sr.sr_dma_dir = SR_DMA_RD;    /* read &sr.sr_addr from device */
  387.  
  388.     err = ioctl(fd, SDIOCSRQ, &sr);
  389.     *erp = sr.sr_esense;
  390.     if (err | sr.sr_io_status) {/* problem reading TOC, return */
  391.     return err | sr.sr_io_status;
  392.     }
  393.  /* record first & last track, and toc data length */
  394.     toc_all->firsttrack = tocr.h.rtr_firsttrack;
  395.     toc_all->lasttrack = tocr.h.rtr_lasttrack;
  396.     nrecords = tocr.h.rtr_lasttrack - tocr.h.rtr_firsttrack + 2;
  397.     toc_data_length = nrecords * sizeof(struct rtr_desc);
  398.     toc_temp_length = GET_2BYTE_UINT(tocr.h.rtr_datalen) - 2;
  399.     nrectemp = toc_data_length / sizeof(struct rtr_desc);
  400.     if (toc_temp_length > toc_data_length) {
  401. #ifdef CD_DEBUG2
  402.         printf("mCD: first = %d, last = %d, nrec=%d,   toc_dl = %d\n",
  403.                 tocr.h.rtr_firsttrack, tocr.h.rtr_lasttrack,
  404.             nrecords, toc_data_length);
  405.         printf("mCD:          switch to --> nrec=%d, rtr_dl-2 = %d\n",
  406.                 nrectemp,  toc_temp_length);
  407. #endif CD_DEBUG2
  408.     toc_data_length = toc_temp_length;
  409.     nrecords = nrectemp;
  410.     } else if (toc_temp_length < toc_data_length) {
  411.         printf("mCD: first = %d, last = %d, nrec=%d,   toc_dl = %d\n",
  412.                 tocr.h.rtr_firsttrack, tocr.h.rtr_lasttrack,
  413.             nrecords, toc_data_length);
  414.         printf("mCD:                but nrectemp=%d, rtr_dl-2 = %d !!\n",
  415.                 nrectemp,  toc_temp_length);
  416.     }
  417.  
  418.  /* prepare for second read toc for the whole thing */
  419.     bzero((char *)&sr, sizeof(sr));
  420.  
  421.     rt10cp = (struct readtoc_43_cmd *) & sr.sr_cdb;
  422.     rt10cp->rt_op_code = C10OP_READTOC_43;
  423.     rt10cp->rt_msf = 1;        /* want msf format */
  424.     rt10cp->rt_starttrack = 0;
  425.     toc_data_length += sizeof(struct rtr_header);
  426.     SET_2BYTE_UINT(rt10cp->rt_length, toc_data_length);
  427.  
  428.     toc_reply = (char *)malloc(toc_data_length);
  429.     bzero((char *)toc_reply, toc_data_length);
  430.     sr.sr_addr = toc_reply;
  431.     sr.sr_dma_max = toc_data_length;
  432.     sr.sr_ioto = 5;        /* time out in 5 seconds */
  433.     sr.sr_dma_dir = SR_DMA_RD;    /* read &sr.sr_addr from device */
  434.  
  435.     err = ioctl(fd, SDIOCSRQ, &sr);
  436.     *erp = sr.sr_esense;
  437.     if (err | sr.sr_io_status) {/* problem reading TOC, return */
  438.     return err | sr.sr_io_status;
  439.     }
  440.  /* successfully read the whole thing, now process it. */
  441.     desc = (struct rtr_desc *) & (toc_reply[4]);    /* skip the header */
  442.     lastsec = 0;
  443.     lasttrack = -1;
  444.     for (i = 0; i < nrecords; i++) {
  445.     track = desc->rtrd_track;
  446.     if (track == 0xaa)
  447.         track = 100;    /* lead-out area */
  448.     if (desc->rtrd_control & DATA_TRACK)
  449.         toc_all->ndata++;
  450.     else if (track != 100)
  451.         toc_all->naudio++;
  452.     toc_all->info[track].control = desc->rtrd_control;
  453.     toc_all->info[track].lblock = (desc->rtrd_addr.msf.hour * 3600)
  454.       + (desc->rtrd_addr.msf.min * 60)
  455.       + desc->rtrd_addr.msf.sec;
  456.     toc_all->info[track].lblock = (toc_all->info[track].lblock * 75)
  457.       + desc->rtrd_addr.msf.frame;
  458.     toc_all->info[track].hour = desc->rtrd_addr.msf.hour;
  459.     toc_all->info[track].min = desc->rtrd_addr.msf.min;
  460.     toc_all->info[track].sec = desc->rtrd_addr.msf.sec;
  461.     toc_all->info[track].frame = desc->rtrd_addr.msf.frame;
  462.     currsec = (desc->rtrd_addr.msf.hour * 3600)
  463.       + (desc->rtrd_addr.msf.min * 60)
  464.       + desc->rtrd_addr.msf.sec;
  465.     if (lasttrack > 0)
  466.         toc_all->info[lasttrack].elapsedSec = currsec - lastsec;
  467.     lasttrack = track;
  468.     lastsec = currsec;
  469.     desc++;
  470.     }
  471.     toc_all->info[100].elapsedSec = (toc_all->info[100].hour * 3600)
  472.       + (toc_all->info[100].min * 60)
  473.       + toc_all->info[100].sec;
  474.  
  475. #ifdef CD_DEBUG
  476.  /* print the table of contents to stderr */
  477.     printf("\n           start time    time elapsed\n");
  478.     for (i = toc_all->firsttrack; i <= toc_all->lasttrack; i++) {
  479.     printf("Track %2d:  %d:%02d:%02d-%02d %c  %02d:%02d\n", i,
  480.            toc_all->info[i].hour, toc_all->info[i].min,
  481.            toc_all->info[i].sec,
  482.            toc_all->info[i].frame,
  483.            toc_all->info[i].control & DATA_TRACK ? 'D' : 'A',
  484.            toc_all->info[i].elapsedSec / 60,
  485.            toc_all->info[i].elapsedSec % 60);
  486.     }
  487.     printf("Track LO:  %d:%02d:%02d-%02d %c\n",
  488.        toc_all->info[100].hour, toc_all->info[100].min,
  489.        toc_all->info[100].sec,
  490.        toc_all->info[100].frame,
  491.        toc_all->info[100].control & DATA_TRACK ? 'D' : 'A');
  492. #endif
  493.  
  494.     if (toc_reply != NULL)
  495.     free(toc_reply);
  496.     return err | sr.sr_io_status;
  497. }
  498.  
  499.  
  500. /**************************************************************************
  501.  *   do_readsubchannel_42
  502.  *
  503.  *    This is only here for reference purposes.  Almost all programs
  504.  *      interested in the information from readsubchannel should be using
  505.  *    routines like do_readcurrentposition_42 and do_readmediacatnum_42.
  506.  */
  507. int
  508. do_readsubchannel_42(int fd, int msf, int subq, int page, int track,
  509.              struct sc_reply * scrp, struct esense_reply * erp)
  510. {
  511.     struct scsi_req     sr;
  512.     struct read_subchannel_42_cmd *rscp;
  513.     int                 err;
  514.  
  515.     bzero((char *)&sr, sizeof(sr));
  516.  
  517.     rscp = (struct read_subchannel_42_cmd *) & sr.sr_cdb;
  518.     rscp->rsc_op_code = C10OP_READSUBCHANNEL_42;
  519.     rscp->rsc_msf = msf;
  520.     rscp->rsc_subq = subq;
  521.     rscp->rsc_dformat = page;
  522.     rscp->rsc_track = track;
  523.     SET_2BYTE_UINT(rscp->rsc_length, sizeof(struct sc_reply));
  524.  
  525.     sr.sr_addr = (char *)scrp;
  526.     sr.sr_dma_max = sizeof(struct sc_reply);
  527.     sr.sr_ioto = 5;        /* time out in 5 seconds */
  528.     sr.sr_dma_dir = SR_DMA_RD;
  529.  
  530.     err = ioctl(fd, SDIOCSRQ, &sr);
  531.     *erp = sr.sr_esense;
  532.     return err | sr.sr_io_status;
  533. }
  534.  
  535.  
  536. /**************************************************************************
  537.  *   do_readcurrentposition_42
  538.  *
  539.  *    This is really the "read sub-channel data" command with a few of
  540.  *      the fields automatically filled in.
  541.  */
  542. int
  543. do_readcurrentposition_42(int fd, struct rsc_cur_pos_reply * curpos,
  544.               struct esense_reply * erp)
  545. {
  546.     struct scsi_req     sr;
  547.     struct sc_reply     scrp;
  548.     struct read_subchannel_42_cmd *rscp;
  549.     u_int               tempUint;
  550.     int                 err;
  551.  
  552.     bzero((char *)&sr, sizeof(sr));
  553.     bzero((char *)&scrp, sizeof(scrp));
  554.  
  555.     rscp = (struct read_subchannel_42_cmd *) & sr.sr_cdb;
  556.     rscp->rsc_op_code = C10OP_READSUBCHANNEL_42;
  557.     rscp->rsc_msf = 1;        /* want MSF (not LBA) format for times */
  558.     rscp->rsc_subq = 1;        /* want to get Q subchannel data */
  559.     rscp->rsc_dformat = 1;    /* want page 1 of Q subchannel data */
  560.     rscp->rsc_track = 0;    /* track is irrelevent for page 1 req */
  561.     SET_2BYTE_UINT(rscp->rsc_length, sizeof(struct sc_reply));
  562.  
  563.     sr.sr_addr = (char *)&scrp;
  564.     sr.sr_dma_max = sizeof(struct sc_reply);
  565.     sr.sr_ioto = 5;        /* time out in 5 seconds */
  566.     sr.sr_dma_dir = SR_DMA_RD;
  567.  
  568.     err = ioctl(fd, SDIOCSRQ, &sr);
  569.     *erp = sr.sr_esense;
  570.     curpos->track = scrp.u.u_scr_cur_pos.sc1_track;
  571.     curpos->index = scrp.u.u_scr_cur_pos.sc1_index;
  572.     curpos->rsc_control = scrp.u.u_scr_cur_pos.sc1_control;
  573.     curpos->rsc_audio_status = scrp.scr_header.sch_astatus;
  574.  
  575.     if (rscp->rsc_msf == 1) {    /* ie, msf formatted times */
  576.     curpos->abs_logical_block = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.sec
  577.       + (scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.min * 60)
  578.       + (scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.hour * 3600);
  579.     curpos->abs_logical_block = (curpos->abs_logical_block * 75)
  580.       + scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.frame;
  581.     curpos->abs_hour = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.hour;
  582.     curpos->abs_min = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.min;
  583.     curpos->abs_sec = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.sec;
  584.     curpos->abs_frame = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.frame;
  585.     if (curpos->abs_min >= 60) {
  586.         curpos->abs_hour++;
  587.         curpos->abs_min -= 60;
  588.     }
  589.     curpos->rel_logical_block = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.sec
  590.       + (scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.min * 60)
  591.       + (scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.hour * 3600);
  592.     curpos->rel_logical_block = (curpos->rel_logical_block * 75)
  593.       + scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.frame;
  594.     curpos->rel_hour = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.hour;
  595.     curpos->rel_min = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.min;
  596.     curpos->rel_sec = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.sec;
  597.     curpos->rel_frame = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.frame;
  598.     if (curpos->rel_min >= 60) {
  599.         curpos->rel_hour++;
  600.         curpos->rel_min -= 60;
  601.     }
  602.     } else {            /* ie, lba formatted times */
  603.     tempUint = GET_4BYTE_UINT(scrp.u.u_scr_cur_pos.sc1_abs_addr.lba.lblock);
  604.     curpos->abs_logical_block = tempUint;
  605.     curpos->abs_frame = tempUint % 75;
  606.     curpos->abs_sec = tempUint / 75;
  607.     curpos->abs_min = curpos->abs_sec / 60;
  608.     curpos->abs_sec = curpos->abs_sec % 60;
  609.     if (curpos->abs_min >= 60) {
  610.         curpos->abs_hour++;
  611.         curpos->abs_min -= 60;
  612.     }
  613.     tempUint = GET_4BYTE_UINT(scrp.u.u_scr_cur_pos.sc1_rel_addr.lba.lblock);
  614.     curpos->rel_logical_block = tempUint;
  615.     curpos->rel_frame = tempUint % 75;
  616.     curpos->rel_sec = tempUint / 75;
  617.     curpos->rel_min = curpos->rel_sec / 60;
  618.     curpos->rel_sec = curpos->rel_sec % 60;
  619.     if (curpos->rel_min >= 60) {
  620.         curpos->rel_hour++;
  621.         curpos->rel_min -= 60;
  622.     }
  623.     }
  624.  
  625.     return err | sr.sr_io_status;
  626. }
  627.  
  628.  
  629. /**************************************************************************
  630.  *   do_readmediacatnum_42
  631.  *
  632.  *    This is really the "read sub-channel data" command with a few of
  633.  *      the fields automatically filled in.
  634.  */
  635. int
  636. do_readmediacatnum_42(int fd, struct rsc_media_catnum_reply * catnum,
  637.               struct esense_reply * erp)
  638. {
  639.     struct scsi_req     sr;
  640.     struct sc_reply     scrp;
  641.     struct read_subchannel_42_cmd *rscp;
  642.     int                 err;
  643.  
  644.     bzero((char *)&sr, sizeof(sr));
  645.     bzero((char *)&scrp, sizeof(scrp));
  646.  
  647.     rscp = (struct read_subchannel_42_cmd *) & sr.sr_cdb;
  648.     rscp->rsc_op_code = C10OP_READSUBCHANNEL_42;
  649.     rscp->rsc_msf = 0;        /* MSF format is irrelevent for this */
  650.     rscp->rsc_subq = 1;        /* want to get Q subchannel data */
  651.     rscp->rsc_dformat = 2;    /* want page 2 of Q subchannel data */
  652.     rscp->rsc_track = 0;    /* track is irrelevent for page 2 req */
  653.     SET_2BYTE_UINT(rscp->rsc_length, sizeof(struct sc_reply));
  654.  
  655.     sr.sr_addr = (char *)&scrp;
  656.     sr.sr_dma_max = sizeof(struct sc_reply);
  657.     sr.sr_ioto = 10;        /* time out in 10 seconds */
  658.     sr.sr_dma_dir = SR_DMA_RD;
  659.  
  660.     err = ioctl(fd, SDIOCSRQ, &sr);
  661.     *erp = sr.sr_esense;
  662.     catnum->catnum_isSet = scrp.u.u_scr_med_cat.sc2_mcval;
  663.     memcpy(catnum->media_catnum, scrp.u.u_scr_med_cat.sc2_med_cat, 15);
  664.  
  665.  /*
  666.   * note that many CDs have mcval set on, but the media-cat# is zero... Also
  667.   * note that different drives return the media-cat# in different formats...  
  668.   */
  669.     bzero((char *)&scrp.u.u_scr_med_cat.sc2_med_cat, 15);    /* = no catnum */
  670.     if (!memcmp(catnum->media_catnum, scrp.u.u_scr_med_cat.sc2_med_cat, 15))
  671.     catnum->catnum_isSet = 0;
  672.     if (!memcmp(catnum->media_catnum, "000000000000000", 15))
  673.     catnum->catnum_isSet = 0;
  674.  
  675.     return err | sr.sr_io_status;
  676. }
  677.  
  678.  
  679. /**************************************************************************
  680.  *   do_playbackstatus_c4
  681.  *
  682.  *    Find out the position and status (playing, paused, whatever) of
  683.  *      the CD drive.  Also picks up the current volume settings.  Note
  684.  *      that this is probably Sony-specific.
  685.  */
  686. int
  687. do_playbackstatus_c4(int fd, struct pb_status_reply * pbstatus,
  688.              struct esense_reply * erp)
  689. {
  690.     struct scsi_req     sr;
  691.     struct playback_statuscontrol_cmd *pbcp;
  692.     struct playback_c4c9_data pbdata;
  693.     u_int               tempUint;
  694.     int                 err;
  695.  
  696.     bzero((char *)&sr, sizeof(sr));
  697.  
  698.     pbcp = (struct playback_statuscontrol_cmd *) & sr.sr_cdb;
  699.     pbcp->pb_opcode = C10OP_PLAYBACKSTATUS_C4;
  700.     SET_2BYTE_UINT(pbcp->pb_length, sizeof(struct playback_c4c9_data));
  701.  
  702.     bzero((char *)&pbdata, sizeof(pbdata));
  703.     sr.sr_addr = (char *)&pbdata;
  704.     sr.sr_dma_max = sizeof(struct playback_c4c9_data);
  705.     sr.sr_ioto = 1;        /* time out in 1 second */
  706.     sr.sr_dma_dir = SR_DMA_RD;
  707.  
  708.     err = ioctl(fd, SDIOCSRQ, &sr);
  709.     *erp = sr.sr_esense;
  710.  
  711.  /*
  712.   * copy information from platform-specific (bigendian) layout to one that
  713.   * matches the current platform 
  714.   */
  715.     bzero((char *)pbstatus, sizeof(struct pb_status_reply));
  716.     pbstatus->pbs_audio_status = pbdata.pbd_audio_status;
  717.     pbstatus->pbs_ch0_sel = pbdata.pbd_ch0_sel;
  718.     pbstatus->pbs_ch0_vol = pbdata.pbd_ch0_vol;
  719.     pbstatus->pbs_ch1_sel = pbdata.pbd_ch1_sel;
  720.     pbstatus->pbs_ch1_vol = pbdata.pbd_ch1_vol;
  721.     pbstatus->pbs_ch2_sel = pbdata.pbd_ch2_sel;
  722.     pbstatus->pbs_ch2_vol = pbdata.pbd_ch2_vol;
  723.     pbstatus->pbs_ch3_sel = pbdata.pbd_ch3_sel;
  724.     pbstatus->pbs_ch3_vol = pbdata.pbd_ch3_vol;
  725.  
  726.  /* the cd-address is returned in both addressing formats */
  727.     if (pbdata.pbd_lbamsf == 1) {    /* ie, msf formatted times */
  728.     if (pbdata.pbd_cd_addr.msf.min == 255) {
  729.     /* if min = 255, then we're really before the */
  730.     /* start of the first track... */
  731.         pbdata.pbd_cd_addr.msf.min = 0;
  732.         pbdata.pbd_cd_addr.msf.sec = 0;
  733.         pbdata.pbd_cd_addr.msf.frame = 75 - pbdata.pbd_cd_addr.msf.frame;
  734.     }
  735.     pbstatus->pbs_logical_block = pbdata.pbd_cd_addr.msf.sec
  736.       + (pbdata.pbd_cd_addr.msf.min * 60)
  737.       + (pbdata.pbd_cd_addr.msf.hour * 3600);
  738.     pbstatus->pbs_logical_block = (pbstatus->pbs_logical_block * 75)
  739.       + pbdata.pbd_cd_addr.msf.frame;
  740.     pbstatus->pbs_hour = pbdata.pbd_cd_addr.msf.hour;
  741.     pbstatus->pbs_min = pbdata.pbd_cd_addr.msf.min;
  742.     pbstatus->pbs_sec = pbdata.pbd_cd_addr.msf.sec;
  743.     pbstatus->pbs_frame = pbdata.pbd_cd_addr.msf.frame;
  744.     if (pbstatus->pbs_min >= 60) {
  745.         pbstatus->pbs_hour++;
  746.         pbstatus->pbs_min -= 60;
  747.     }
  748.     } else {            /* ie, lba formatted times */
  749.     tempUint = GET_4BYTE_UINT(pbdata.pbd_cd_addr.lba.lblock);
  750.     pbstatus->pbs_logical_block = tempUint;
  751.     pbstatus->pbs_frame = tempUint % 75;
  752.     pbstatus->pbs_sec = tempUint / 75;
  753.     pbstatus->pbs_min = pbstatus->pbs_sec / 60;
  754.     pbstatus->pbs_sec = pbstatus->pbs_sec % 60;
  755.     if (pbstatus->pbs_min == 255) {
  756.     /* if min = 255, then we're really before the */
  757.     /* start of the first track... */
  758.         pbstatus->pbs_min = 0;
  759.         pbstatus->pbs_sec = 0;
  760.         pbstatus->pbs_frame = 75 - pbstatus->pbs_frame;
  761.         pbstatus->pbs_logical_block = pbstatus->pbs_frame;
  762.     }
  763.     if (pbstatus->pbs_min >= 60) {
  764.         pbstatus->pbs_hour++;
  765.         pbstatus->pbs_min -= 60;
  766.     }
  767.     }
  768.  
  769.     return err | sr.sr_io_status;
  770. }
  771.  
  772.  
  773. /**************************************************************************
  774.  *   do_playbackvolume_c9
  775.  *
  776.  *    Change the current volume settings, using the playback control
  777.  *      command (which is probably Sony-specific).
  778.  */
  779. int
  780. do_playbackvolume_c9(int fd, int leftVolume, int rightVolume,
  781.              struct esense_reply * erp)
  782. {
  783.     struct scsi_req     sr;
  784.     struct playback_statuscontrol_cmd *pbcp;
  785.     struct playback_c4c9_data pbdata;
  786.     int                 err;
  787.  
  788.     bzero((char *)&sr, sizeof(sr));
  789.  
  790.     pbcp = (struct playback_statuscontrol_cmd *) & sr.sr_cdb;
  791.     pbcp->pb_opcode = C10OP_PLAYBACKCONTROL_C9;
  792.     SET_2BYTE_UINT(pbcp->pb_length, sizeof(struct playback_c4c9_data));
  793.  
  794.     bzero((char *)&pbdata, sizeof(pbdata));
  795.     pbdata.pbd_ch0_sel = 1;
  796.     pbdata.pbd_ch0_vol = leftVolume;
  797.     pbdata.pbd_ch1_sel = 2;
  798.     pbdata.pbd_ch1_vol = rightVolume;
  799.  
  800.     sr.sr_addr = (char *)&pbdata;
  801.     sr.sr_dma_max = sizeof(struct playback_c4c9_data);
  802.     sr.sr_ioto = 1;        /* time out in 1 second */
  803.     sr.sr_dma_dir = SR_DMA_WR;
  804.  
  805.     err = ioctl(fd, SDIOCSRQ, &sr);
  806.     *erp = sr.sr_esense;
  807.     return err | sr.sr_io_status;
  808. }
  809.  
  810.  
  811. /**************************************************************************
  812.  *   do_modesense_pc_E
  813.  *
  814.  *    This is just the do_modesense command from scsi_commands, except
  815.  *    that it's setup to return page-code E in particular.  Page-code E
  816.  *    is the one for CD-ROM Audio Control parameters.  Declarations of
  817.  *    some structs are also redone (and in cd_cmdsint.h) to make them
  818.  *    more platform-independent.
  819.  */
  820. int
  821. do_modesense_pc_E(int fd, struct cd_volset_reply * volset, struct esense_reply * erp)
  822. {
  823.     struct scsi_req     sr;
  824.     struct mode_sense_select_cmd *mscp;
  825.     struct mode_sense_select_reply msrp;
  826.     int                 err;
  827.  
  828.     bzero((char *)&sr, sizeof(sr));
  829.     bzero((char *)&msrp, sizeof(msrp));
  830.  
  831.     mscp = (struct mode_sense_select_cmd *) & sr.sr_cdb;
  832.     mscp->msc_opcode = C6OP_MODESENSE;
  833.     mscp->msc_lun = 0;
  834.     mscp->msc_pcf = 0;        /* report current values */
  835.     mscp->msc_page = 0x0E;
  836.     mscp->msc_len = sizeof(msrp);
  837.  
  838.     sr.sr_addr = (char *)&msrp;
  839.     sr.sr_dma_max = sizeof(msrp);
  840.     sr.sr_ioto = 50;        /* using an extended timeout */
  841.     sr.sr_dma_dir = SR_DMA_RD;    /* read &sr.sr_addr from device */
  842.  
  843.     err = ioctl(fd, SDIOCSRQ, &sr);
  844.     *erp = sr.sr_esense;
  845.  
  846.  /*
  847.   * copy information from platform-specific (bigendian) layout to one that
  848.   * matches the current platform 
  849.   */
  850.     bzero((char *)volset, sizeof(struct cd_volset_reply));
  851.     volset->ch0_sel = msrp.u.u_msr_pcE.pce_ch0_sel;
  852.     volset->ch0_vol = msrp.u.u_msr_pcE.pce_ch0_vol;
  853.     volset->ch1_sel = msrp.u.u_msr_pcE.pce_ch1_sel;
  854.     volset->ch1_vol = msrp.u.u_msr_pcE.pce_ch1_vol;
  855.     volset->ch2_sel = msrp.u.u_msr_pcE.pce_ch2_sel;
  856.     volset->ch2_vol = msrp.u.u_msr_pcE.pce_ch2_vol;
  857.     volset->ch3_sel = msrp.u.u_msr_pcE.pce_ch3_sel;
  858.     volset->ch3_vol = msrp.u.u_msr_pcE.pce_ch3_vol;
  859.  
  860.     return err | sr.sr_io_status;
  861. }
  862.  
  863.  
  864. /**************************************************************************
  865.  *   do_modeselect_pc_E
  866.  *
  867.  *    This is basically just the do_modesense_pc_E command reversed,
  868.  *    such that CD volume settings are being set instead of sensed.
  869.  */
  870. int
  871. do_modeselect_pc_E(int fd, int leftVolume, int rightVolume, struct esense_reply * erp)
  872. {
  873.     struct scsi_req     sr;
  874.     struct mode_sense_select_cmd *mscp;
  875.     struct mode_select_alt_reply msarp;
  876.     int                 err;
  877.  
  878.     bzero((char *)&sr, sizeof(sr));
  879.  
  880.     mscp = (struct mode_sense_select_cmd *) & sr.sr_cdb;
  881.     mscp->msc_opcode = C6OP_MODESELECT;
  882.     mscp->msc_lun = 0;
  883.     mscp->msc_len = sizeof(msarp);
  884.  
  885.     sr.sr_addr = (char *)&msarp;
  886.     sr.sr_dma_max = sizeof(msarp);
  887.     sr.sr_ioto = 50;        /* using an extended timeout */
  888.     sr.sr_dma_dir = SR_DMA_WR;    /* write &sr.sr_addr to device */
  889.  
  890.     bzero((char *)&msarp, sizeof(msarp));
  891.     msarp.msar_plh.plh_blkdesclen = 0;    /* using alternate form,  with no
  892.                      * block descriptor */
  893.     msarp.u.u_msar_pcE.pce_pagecode = 0x0E;
  894.     msarp.u.u_msar_pcE.pce_parlen = 0x0E;
  895.     msarp.u.u_msar_pcE.pce_immd = YES;
  896.     msarp.u.u_msar_pcE.pce_ch0_sel = 1;
  897.     msarp.u.u_msar_pcE.pce_ch0_vol = leftVolume;
  898.     msarp.u.u_msar_pcE.pce_ch1_sel = 2;
  899.     msarp.u.u_msar_pcE.pce_ch1_vol = rightVolume;
  900.  
  901.     err = ioctl(fd, SDIOCSRQ, &sr);
  902.  
  903.     *erp = sr.sr_esense;
  904.  
  905.     return err | sr.sr_io_status;
  906. }
  907.